/*
Containers:  brief Definition of container classes from fui.
    Copyright (C) 2012  Jorge E. A. Atala
                        FuDePAN
    This file is part of the Fui Proyect.

    Fui is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Fui is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Fui.  If not, see <http://www.gnu.org/licenses/>.
*/


#ifndef ITERATORS_H
#   define ITERATORS_H
#   include "countingIterator.h"
#   include "transformIterator.h"
#   include "permutationIterator.h"
namespace fui
{
/*! \addtogroup Containers
 *  \addtogroup Fancy_Iterators Fancy Iterators
 *  \ingroup Containers
 *  \{
 */
/*! \p counting_iterator is an iterator which represents a sequence of increasing
 *  values. This iterator is useful for creating an accesible sequence without use
 *  memory allocation. You can save memory and bandwidth.
 *
 *  The following code snippet demonstrates how to create two \p counting_iterator
 *  and make a sum of the elements between theirs.
 *
 *  \code
 *
 * // create iterators
 * fui::counting_iterator<int>::type first(10);
 * fui::counting_iterator<int>::type last = first + 3;
 *
 * first[0]   // returns 10
 * first[1]   // returns 11
 * first[100] // returns 110
 *
 * // sum of [first, last)
 * fui::reduce(first, last);   // returns 33 (i.e. 10 + 11 + 12)
 *  \endcode
 *
 *  \see make_counting_iterator
 */
template<class T>
struct counting_iterator
{
    typedef CountingIterator<T> type;
};

template <class T>
inline CountingIterator<T> make_counting_iterator(const T x)
{
    return CountingIterator<T>(x);
}

/*! \p transform_iterator is an iterator which represents a pointer into a range
 *  of values after transformation by a function. This iterator is useful for
 *  creating a range filled with the result of applying an operation to another range
 *  without either explicitly storing it in memory, or explicitly executing the transformation.
 *  Using \p transform_iterator facilitates kernel fusion by deferring the execution
 *  of a transformation until the value is needed while saving both memory capacity
 *  and bandwidth.
 *
 *  The following code snippet demonstrates how to create a \p transform_iterator
 *  which represents the result of \c sqrtf applied to the contents of a \p device_vector.
 *
 *  \code
 *
 *  // note: functor inherits from unary_function
 *  struct square_root : public fui::unary_function<float,float>::type
 *  {
 *    __host__ __device__
 *    float operator()(float x) const
 *    {
 *      return sqrtf(x);
 *    }
 *  };
 *
 *  int main(void)
 *  {
 *      fui::device_vector<float>::type v(4);
 *      v[0] = 1.0f;
 *      v[1] = 4.0f;
 *      v[2] = 9.0f;
 *      v[3] = 16.0f;
 *
 *      typedef fui::device_vector<float>::type::iterator FloatIterator;
 *
 *      fui::transform_iterator<square_root, FloatIterator>::type iter(v.begin(), square_root());
 *
 *      *iter;   // returns 1.0f
 *      iter[0]; // returns 1.0f;
 *      iter[1]; // returns 2.0f;
 *      iter[2]; // returns 3.0f;
 *      iter[3]; // returns 4.0f;
 *
 *      // iter[4] is an out-of-bounds error
 *  }
 *  \endcode
 *
 *  \see make_transform_iterator
 */
template<class UnaryFunction, class Iterator>
struct transform_iterator
{
    typedef TransformIterator<UnaryFunction, Iterator> type;
};

template <class UnaryFunction, class Iterator>
inline TransformIterator<UnaryFunction, Iterator> make_transform_iterator(const Iterator& it, const UnaryFunction function)
{
    return TransformIterator<UnaryFunction, Iterator>(it, function);
}

/*! \p permutation_iterator is an iterator which takes a pair of vectors, the first one
 *  it's a collection of data and the second one is a collection of indexes, ordered by
 *  the order in we want to access the data elements.
 *
 *  The following code snippet demonstrates how to create a \p permutation_iterator
 *  which represents the result of \c sqrtf applied to the contents of a \p device_vector.
 *
 *  \code
 *
  fui::device_vector<float>::type values(8);
  values[0] = 10.0f;
  values[1] = 20.0f;
  values[2] = 30.0f;
  values[3] = 40.0f;
  values[4] = 50.0f;
  values[5] = 60.0f;
  values[6] = 70.0f;
  values[7] = 80.0f;

  fui::device_vector<int>::type indices(4);
  indices[0] = 2;
  indices[1] = 6;
  indices[2] = 1;
  indices[3] = 3;

  typedef fui::device_vector<float>::type::iterator ElementIterator;
  typedef fui::device_vector<int>::type::iterator   IndexIterator;

  fui::::permutation_iterator<ElementIterator,IndexIterator>::type iter(values.begin(), indices.begin());

  *iter;   // returns 30.0f;
  iter[0]; // returns 30.0f;
  iter[1]; // returns 70.0f;
  iter[2]; // returns 20.0f;
  iter[3]; // returns 40.0f;

  // iter[4] is an out-of-bounds error

  *iter   = -1.0f; // sets values[2] to -1.0f;
  iter[0] = -1.0f; // sets values[2] to -1.0f;
  iter[1] = -1.0f; // sets values[6] to -1.0f;
  iter[2] = -1.0f; // sets values[1] to -1.0f;
  iter[3] = -1.0f; // sets values[3] to -1.0f;

  // values is now {10, -1, -1, -1, 50, 60, -1, 80}
 *  \endcode
 *
 *  \see make_permutation_iterator
 */
template<class ElementIterator, class IndexIterator>
struct permutation_iterator
{
    typedef PermutationIterator<ElementIterator, IndexIterator> type;
};

template <class ElementIterator, class IndexIterator>
inline PermutationIterator<ElementIterator, IndexIterator> make_permutation_iterator(const ElementIterator& it, const IndexIterator& index)
{
    return PermutationIterator<ElementIterator, IndexIterator>(it, index);
}
/*!
 * \}
 */
}
#endif

